/**
 * 使用 API 实现的 webpack 开发服务器
 */
const webpack = require('webpack');
const Koa = require('koa');
const chalk = require('chalk');
const nodemon = require('nodemon');
const rimraf = require('rimraf');
const webpackDevMiddleware = require('./dev');
const webpackHotMiddleware = require('./hot');
const {
    devMiddleware,
    hotMiddleware
} = require('koa-webpack-middleware');

const clientConfig = require('../config/webpack/client.dev');
const serverConfig = require('../config/webpack/server.dev');

const config = require('../config');

// webpack 编译器 hook Promise化
const compilerPromise = compiler => {
    return new Promise((resolve, reject) => {
        compiler.hooks.done.tap('compilerDonePlugin', (stats) => {
            try {
                return resolve(); // 返回一个包含有结果内容的 Promise 
            } catch (e) { return reject('Compolation failed'); }
        })
    })
}

const app = new Koa(); // 创建服务器
const WEBPACK_PROT = config.port + 1;

const start = async () => {
    rimraf.sync('./dist'); // 删除上一次运行打包的结果

    clientConfig.entry.app.unshift(`webpack-hot-middleware/client?path=http://localhost:${WEBPACK_PROT}/__webpack_hmr&timeout=20000`);
    clientConfig.entry.app.unshift(`eventsource-polyfill`);
    clientConfig.output.hotUpdateMainFilename = `[hash].hot-update.json`;
    clientConfig.output.hotUpdateChunkFilename = `[id].[hash].hot-update.js`;
    clientConfig.output.publicPath = `http://localhost:${WEBPACK_PROT}/`;

    serverConfig.output.publicPath = `http://localhost:${WEBPACK_PROT}/`;

    const compilers = webpack([ clientConfig, serverConfig ]).compilers;
    
    const _clientCompiler = compilers[0];
    const _serverCompiler = compilers[1];

    const clientPromise = compilerPromise(_clientCompiler);
    const serverPromise = compilerPromise(_serverCompiler);

    /**
     * 中间件
     */
    // 允许跨域
    app.use(async (ctx, next) => {
        await next();
        let res = ctx.response;
        res.set('Access-Control-Allow-Origin', '*');
    });

    // webpack-dev-middleware
    // app.use(webpackDevMiddleware(_clientCompiler, {
    //     noInfo: false,
    //     quiet: true,
    //     serverSideRender: true,
    //     publicPath: config.public_path
    // }));
    // // webpack-hot-middleware
    // app.use(webpackHotMiddleware(_clientCompiler, {}));

    app.use(devMiddleware(_clientCompiler, {
        noInfo: false,
        quiet: true
    }))

    app.use(hotMiddleware(_clientCompiler));

    // 静态资源处理
    app.use(require('koa-static')('./dist/client'));

    app.listen(WEBPACK_PROT, () => {
        console.log(chalk.green(`webpack dev server started at port ${WEBPACK_PROT}`));
    });

    // 服务端代码更新监听
    _serverCompiler.watch({
        ignored: /node_modules/
    }, (err, stats) => {
        if (err) {
            console.error(err.stack || err);
            if (err.details) {
                console.error(err.details);
            }
            return;
        }
        const info = stats.toJson();
        if (stats.hasErrors()) {
            console.error(info.errors);
        }
        if (stats.hasWarnings()) {
            console.warn(info.warnings);
        }
    });

    await clientPromise;
    await serverPromise;

    // 启用 nodemon 重启服务
    nodemon({
        script: './dist/server/server.js',
        ignore: [
            'src',
            'scripts',
            'config',
            './*.*',
            'dist/client',
            '.vscode'
        ]
    }).on('quit', () => {
       console.log(chalk.red(`Process ended`));
       process.exit();
    }).on('restart', () => {
        console.log(chalk.green(`Server side app has been restarted`));
    }).on('error', () => {
        console.log(chalk.red(`An error occured. Exiting`))
        process.exit(1);
    })
}

start();